/**
 * @method Lazy 懒加载解决方案
 * @author Lkx
 *
 * @method use  启用懒加载
 */

(function (factory) {

  if (typeof exports === "object" && typeof module !== "undefined") {
    module.exports = factory();
  } else {
    window.Kxui.lazy = window.kxui.lazy = factory();
  }

}(function () {

  "use strict";

  const win = window;
  const doc = win.document;
  const Kxui = win.Kxui;
  const method = Kxui.method;

  // 全局错误样式
  // 通过主入口注册，达到全模块统一错误输出
  const Kxui_throws_style = win.Kxui_throws_style;

  /**
   * @method 异常抛出
   * @param  {number} num       抛出错误文案的编号
   * @param  {string} parameter 抛出错误的参数
   */
  const throws = (num, parameter) => {
    if (Kxui.configuration.debug) {
      const nums = {};
      nums[0] = `依赖模块 {${parameter}} 未被提前加载`;
      console.error(`%cKxui.lazy%c (${Kxui.about.version})\n%c${nums[num]}，请检查修改。`, Kxui_throws_style[0], Kxui_throws_style[1], Kxui_throws_style[2]);
    }
  };

  // 前置依赖判断
  // 判断当前模块是否前置依赖均加载完毕
  const pre_dependence = () => {
    if (method) {
      return true;
    } else {
      throws(0, "method");
      return false;
    }
  };

  /**
   * @method 判断是否有滚动条
   * @param  {object} element 判断对象
   */
  const has_scrolled = (element) => {
    if (element.scrollHeight > element.clientHeight) {
      return true;
    } else {
      return element.offsetHeight - element.clientHeight > 0;
    }
  };

  class Load {

    constructor(parameter) {
      this.error = parameter.error;
      this.loading = parameter.loading;
      this.initialization();
    }

    // 懒加载初始化
    // 当图片数量发生变化时也将会执行
    initialization() {
      this.roll = [];
      this.operation_img = doc.querySelectorAll("img[lazy-src]");
      this.operation_img_length = this.operation_img.length;
      this.rolling_node();
      this.rolling_event();
    }

    /**
     * @method 循环图片获取其所属的滚动父节点
     * @param  {object} polling_array 轮询组
     */
    rolling_node(polling_array = {}) {
      const operation_img = method.data_defense(polling_array, ["img"]) || this.operation_img;

      // 记录当前临时数据组
      let operation_parent = [];

      // 循环图片获取其所属的滚动父节点
      for (let i = 0; i < operation_img.length; i++) {
        const img = operation_img[i];

        // 图片加载过程
        // 若是存在 loading 路径则进入
        if (this.loading && !img.src) {
          img.src = this.loading;
        }

        // 判断当前父节点是否存在滚动条
        const parent =  method.data_defense(polling_array, ["box", "parentNode"]) || img.parentNode;
        if (has_scrolled(parent)) {
          this.combination(this.roll, parent, img);
        } else if (parent.tagName === "BODY") {
          this.combination(this.roll, win, img);
        } else {
          this.combination(operation_parent, parent, img);
        }
      }

      // 进行轮询操作
      // 当父节点不是滚动对象时进入
      if (operation_parent.length !== 0) {
        for (let p = 0; p < operation_parent.length; p++) {
          const operation_parent_p = operation_parent[p];
          this.rolling_node(operation_parent_p);
        }
      }
    }

    /**
     * @method 数据组合
     * @param  {array}  dom 需要组合至的数组
     * @param  {object} box 滚动盒子
     * @param  {object} img 所属图片
     */
    combination(dom, box, img) {

      // 用于重新生成新的对象
      const generation = () => {
        const data = {};
        data.box = box;
        data.box_style = {};
        data.box_style.top = box.offsetTop;
        data.box_style.left = box.offsetLeft;
        data.img = [img];
        dom.push(data);
      };

      if (dom.length === 0) {
        generation();
      } else {
        for (let r = 0; r < dom.length; r++) {
          const roll = dom[r];
          if (roll.box === box) {
            roll.img.push(img);
            break;
          } else if (r === dom.length - 1) {
            generation();
            break;
          }
        }
      }
    }

    // 逻辑处理及事件运行
    // 初始化进行懒加载
    // 监听滚动盒子进行懒加载
    rolling_event() {
      for (let i = 0; i < this.roll.length; i++) {
        const roll = this.roll[i];
        this.lazy_load(roll);
        roll.box.onscroll = () => {
          this.lazy_load(roll);
        };
      }
      this.monitor();
    }

    // 监听页面变化进行实时更新
    // 此方法进行监听页面数据变化，当图片数量发生变化时进行数据修改
    monitor() {
      const mutation_observer = win.MutationObserver || win.WebKitMutationObserver || win.MozMutationObserver;
      const config = { subtree: true, childList: true };
      const observer = new mutation_observer((mutations) => {
        mutations.forEach((record) => {
          if (record.type === "childList") {
            const operation_img_length = doc.querySelectorAll("img[lazy-src]").length;
            if (operation_img_length !== this.operation_img_length) {
              for (let i = 0; i < this.roll.length; i++) { this.roll[i].box.onscroll = false; }
              this.initialization();
              observer.disconnect();
            }
          }
        });
      });
      observer.observe(doc.querySelector("body"), config);
    }

    /**
     * @method 懒加载逻辑
     * @param  {object} roll 滚动参数
     */
    lazy_load(roll) {
      const roll_width = roll.box.offsetWidth || win.innerWidth;
      const roll_height = roll.box.offsetHeight || win.innerHeight;
      const scroll_top = method.data(roll.box.scrollTop, "number") ? roll.box.scrollTop : doc.documentElement.scrollTop || doc.body.scrollTop;
      const scroll_left = method.data(roll.box.scrollLeft, "number") ? roll.box.scrollLeft : doc.documentElement.scrollLeft || doc.body.scrollLeft;

      for(let i = 0; i < roll.img.length; i++) {
        const img = roll.img[i];
        const img_src = img.getAttribute("lazy-src");

        // 只有当未加载时进入
        // 当前图片是否已经加载
        if (img.src !== img_src) {
          const img_width = img.offsetWidth;
          const img_height = img.offsetHeight;
          const img_top = img.offsetTop - method.data_defense(roll, ["box_style", "top"]);
          const img_left = img.offsetLeft - method.data_defense(roll, ["box_style", "left"]);

          // 图片必须进入视野才能开始进行加载
          // 分别判断纵向滚动条及横向滚动条，均要进入视野方可进行加载
          const longitudinal = (roll_height + scroll_top) >= img_top && (img_height + img_top) >= scroll_top;
          const transverse = (roll_width + scroll_left) >= img_left && (img_width + img_left) >= scroll_left;
          if (longitudinal && transverse) {
            const temp = new Image();
            temp.src = img_src;

            // 图片加载完毕
            temp.onload = () => { img.src = img_src; };

            // 图片加载失败
            // 若是存在失败图片路径则进入
            if (this.error) {
              temp.onerror = () => { img.src = this.error; };
            }
          }
        }
      }
    }
  }

  class Lazy {

    constructor() {
      this.name = "Lazy";
      this.info = "Lazy Load Solution";
    }

    /**
     * @method 启用懒加载
     * @param  {object} parameter 懒加载参数
     *
     * Lazy.use(parameter)
     */
    use(parameter = {}) {
      if (pre_dependence()) { new Load(parameter); }
    }
  }

  return new Lazy();

}));
